package fr.bludwarf.skywarrior.ile;

import fr.bludwarf.skywarrior.exceptions.ConstructionImpossibleException;
import fr.bludwarf.skywarrior.exceptions.EvenementInconnuOublieException;
import fr.bludwarf.skywarrior.global.Entite;
import fr.bludwarf.skywarrior.global.EtatMonde;
import fr.bludwarf.skywarrior.global.Temps;
import fr.bludwarf.skywarrior.global.TimeFactorInconnu;

public abstract class Progression<E extends Entite>
{

	/** Durée de construction restante */
	private double _tempsRestant;
	private boolean _commencee = false;
	/** La construction a été commencée (ressource déjà dépensées) si != null */
	private Temps _debut = null;
	/** Durée réelle de la construction une fois terminée */
	private double _dureeReelle = 0;
	
	/** entité concernée */
	E _entite;

	public Progression(E entite)
	{
		super();
		_entite = entite;
	}
	
	public Progression(Progression<E> p)
	{
		_entite = p._entite;
		_tempsRestant = p._tempsRestant;
		_debut = p._debut;
		_commencee = p._commencee;
		_dureeReelle = p._dureeReelle;
	}
	
	public Progression(Progression<E> construction, E entite)
	{
		this(construction);
		_entite = entite;
	}

	public abstract double getDureeEstimee(EtatMonde etatMonde) throws Exception;
	
	public E getEntite()
	{
		return _entite;
	}
	
	public boolean aEteCommencee()
	{
		return _commencee;
	}

	/**
	 * @param debut 
	 * @return la quantité de ressource utilisées pour commencer la construction
	 * @throws TimeFactorInconnu 
	 * @since 2 nov. 2011
	 */
	public void commencer(EtatMonde etatMonde) throws Exception
	{
		_debut = etatMonde.getTemps();
		_commencee = true;
		_tempsRestant = getDureeEstimee(etatMonde);
	}
	
	public double getTempsRestant(EtatMonde etatMonde) throws Exception
	{
		if (aEteCommencee())
		{
			return _tempsRestant;
		}
		else
		{
			return getDureeEstimee(etatMonde);
		}
	}
	
	public boolean estTerminee()
	{
		return _tempsRestant <= 0;
	}

	public void applyTimeFactor(final double timeFactor) {
		_tempsRestant *= timeFactor;
	}

	/**
	 * @param temps
	 * @return la durée qu'à pris la construction
	 */
	public double terminer(Temps temps)
	{
		_dureeReelle = temps.tempsEcouleDepuis(_debut);
		return _dureeReelle;
	}
	
	public double getDureeReelle()
	{
		return _dureeReelle;
	}

	public void setTempsRestantForXML(String dureeStr)
	{
		if (dureeStr == null)
		{
			_commencee = false;
		}
		else
		{
			_commencee = true;
			_tempsRestant = Temps.parseDuree(dureeStr);
		}
	}
	
	public Temps getDebut()
	{
		return _debut;
	}

	/**
	 * @param temps
	 * @return le temps qui n'a pas été utilisé dans la construction (peut être utilisé pour la construction suivante), 0 si aucun temps restant
	 * @throws ConstructionImpossibleException si le bâtiment n'a pas été commencé
	 * @throws EvenementInconnuOublieException 
	 * @since 8 nov. 2011
	 */
	public double avancer(final double temps) throws Exception
	{		
		// Temps qu'il resta en rab après la construction
		double rab = 0;
		try
		{
			Temps.decrementer(temps, _tempsRestant);
		}
		catch (final EvenementInconnuOublieException e)
		{
			rab = 0;
		}
		
		// On continue la construction
		_tempsRestant = Temps.decrementer(_tempsRestant, temps);
		
		if (rab > 0)
		{
			System.err.println("Il ne devrait pas rester de rab pour la construction " + this);
		}
		
		return rab;
	}
	
	public String toString(EtatMonde etatMonde) throws Exception {
		String temps;
		try
		{
			temps = Temps.timeToString(getTempsRestant(etatMonde));
		} catch (TimeFactorInconnu e)
		{
			temps = "?";
		}
		return (aEteCommencee() ? "*" : "") + getObjet() + "(" + temps + ")";
	}

	/**
	 * @return nom de l'objet concerné (unité par exemple pour une construction)
	 */
	public abstract String getObjet();

}